package com.franklin.validation.core.params;

import com.franklin.validation.core.annotations.NotNullForMap;
import com.franklin.validation.core.annotations.ParamCheck;

import com.franklin.validation.core.annotations.ParamCheckSub;
import com.franklin.validation.core.annotations.RequestParamRule;
import com.franklin.validation.core.constants.Constants;
import com.franklin.validation.core.entity.CheckJsonEntity;
import com.franklin.validation.core.entity.ParamEntity;
import com.franklin.validation.core.interfaces.Rule;
import com.franklin.validation.core.utils.DataCheckUtil;
import com.franklin.validation.core.utils.ReflectionUtil;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.regex.Pattern;

/**
 * Description : V2新增集合参数校验
 * Create By: Franklin
 * Date : 2020/6/1 16:52
 */
@Component
@RequestParamRule(version = "2")
public class RequestParamRuleV2 implements Rule<CheckJsonEntity,String> {

    @Override
    public String check(CheckJsonEntity input) {
        Map<String,Object> params = input.getParams();
        NotNullForMap notNullForMap = input.getNotNullForMap();
        try {
            Arrays.stream(notNullForMap.params())
                    .forEach(paramCheck -> {
                        Object param = params.get(paramCheck.value());
                        Class type = paramCheck.type();
                        String result = null;
                        ParamEntity paramEntity = ParamEntity.getEntity(paramCheck);
                        if (type == String.class){
                            result = checkParam(param,paramEntity,params);
                        }else if (type == Date.class){
                            result = checkParam(param,paramEntity,params);
                        }else if (type == List.class){
                            result = checkParamList(param,paramCheck,params);
                        }else if (type == Map.class){
                            result = checkParamMap(param,paramCheck,params);
                        }
                        if (!Constants.SUCCESS_STR.equals(result)){
                            throw new RuntimeException(result);
                        }
                    });
        } catch (Exception e) {
            return e.getMessage();
        }
        return Constants.SUCCESS_STR;
    }

    /**
     * 检查Map集合
     * @param param
     * @param paramCheck
     * @param params
     * @return
     */
    private String checkParamMap(Object param, ParamCheck paramCheck, Map<String, Object> params) {
        Map<String,Object> map;
        try{
            map = (Map<String,Object>)param;
            String x = checkColl(paramCheck, map);
            if (x != null) return x;
            String split = checkSub(paramCheck, map, -1);
            if (split != null) return split;
        } catch (Exception e){
            return getCollectionResultString(paramCheck, e);
        }
        return Constants.SUCCESS_STR;
    }

    /**
     * 检查子条件
     * @param paramCheck
     * @param o
     * @param index
     * @return
     */
    private String checkSub(ParamCheck paramCheck, Object o, int index) {
        if (o instanceof String || o instanceof Number){
            o = DataCheckUtil.trim(o);
            if (DataCheckUtil.isEmpty(o)){
                if (DataCheckUtil.isNotEmpty(paramCheck.message())){
                    return paramCheck.message();
                }
                return paramCheck.value();
            }
        }else {
            Map map = (Map) o;
            for (ParamCheckSub paramCheckSub : paramCheck.subParams()) {
                ParamEntity paramEntity = ParamEntity.getEntity(paramCheckSub);
                String result = checkParam(map.get(paramEntity.getValue()), paramEntity, map);
                if(!Constants.SUCCESS_STR.equals(result)){
                    String msg;
                    boolean isMsg = result.startsWith(Constants.MESSAGE);
                    if (isMsg){
                        msg = result.split(":")[1];
                    }else {
                        msg = result;
                    }
                    if (DataCheckUtil.isEmpty(paramCheck.message())){
                        String s = paramCheck.value()
                                + (index >= 0 ? ("[" + index + "]") : "")
                                + msg;
                        if (isMsg){
                            return Constants.MESSAGE + s;
                        }else {
                            return s;
                        }
                    }else {
                        return paramCheck.message();
                    }
                }
            }
        }
        return Constants.SUCCESS_STR;
    }

    /**
     * 检查List集合
     * @param param
     * @param paramCheck
     * @param params
     * @return
     */
    private String checkParamList(Object param, ParamCheck paramCheck, Map<String, Object> params) {
        List list;
        try{
            list = (List)param;
            String x = checkColl(paramCheck, list);
            if (x != null) return x;
            for (int i = 0; i < list.size(); i++) {
                String s = checkSub(paramCheck, list.get(i),i);
                if (!Constants.SUCCESS_STR.equals(s)){
                    return s;
                }
            }
        } catch (Exception e){
            return getCollectionResultString(paramCheck, e);
        }
        return Constants.SUCCESS_STR;
    }

    private String checkColl(ParamCheck paramCheck, Object list) {
        boolean isEmpty = DataCheckUtil.isEmpty(list);
        boolean hasMessage = DataCheckUtil.isNotEmpty(paramCheck.message());
        if (paramCheck.required()){
            if (isEmpty){
                if (hasMessage){
                    return Constants.MESSAGE + paramCheck.message();
                }
                return paramCheck.value();
            }
        }
        return null;
    }

    private String getCollectionResultString(ParamCheck paramCheck, Exception e) {
        if (e instanceof NullPointerException){
            if (!paramCheck.required()){
                return Constants.SUCCESS_STR;
            }
            return paramCheck.value();
        }
        if (e instanceof ClassCastException){
            if (DataCheckUtil.isNotEmpty(paramCheck.message())){
                return Constants.MESSAGE + paramCheck.message();
            }
            return paramCheck.value();
        }
        return e.getMessage();
    }

    /**
     * 检查一般字符串
     * @param param
     * @param paramCheck
     * @param params
     * @return
     */
    private String checkParam(Object param, ParamEntity paramCheck, Map<String,Object> params){
        boolean isEmpty = DataCheckUtil.isEmpty(param);
        boolean isSysDefault = ReflectionUtil.isSystemDefaultValue(paramCheck.getDefaultValue());
        boolean patternPass = false;
        boolean lengthPass = false;
        boolean hasPattern = DataCheckUtil.isNotEmpty(paramCheck.getPattern());
        boolean hasMessage = DataCheckUtil.isNotEmpty(paramCheck.getMessage());
        param = DataCheckUtil.trim(param);
        if (!isEmpty &&  hasPattern && String.class == paramCheck.getType()){
            patternPass = Pattern.compile(paramCheck.getPattern()).matcher((String)param).matches();
        }else if (hasPattern && Date.class == paramCheck.getType()){
            patternPass = DataCheckUtil.checkDate((String)param,paramCheck.getPattern());
        }
        if (!hasPattern){
            patternPass = true;
        }
        if (!isEmpty && String.class == paramCheck.getType()){
            String str = (String) param;
            if (str.length() <= paramCheck.getMax() && str.length() >= paramCheck.getMin()){
                lengthPass = true;
            }
        }else {
            lengthPass = true;
        }
        if (paramCheck.isRequired()){
            //必填
            if (isEmpty){
                //为空，判断有没有默认值
                if (isSysDefault){
                    if (hasMessage){
                        return Constants.MESSAGE + paramCheck.getMessage();
                    }
                    return paramCheck.getValue();
                }
                params.put(paramCheck.getValue(),paramCheck.getDefaultValue());
            } else if (!patternPass || !lengthPass){
                if (isSysDefault){
                    if (hasMessage){
                        return Constants.MESSAGE + paramCheck.getMessage();
                    }
                    return paramCheck.getValue();
                }
                params.put(paramCheck.getValue(),paramCheck.getDefaultValue());
            }
        }else {
            //非必填
            if (isEmpty){
                //为空判断是否有默认值
                if (isSysDefault){
                    params.remove(paramCheck.getValue());
                }else {
                    params.put(paramCheck.getValue(),paramCheck.getDefaultValue());
                }
            }else {
                String x = checkPatternAndLenght(paramCheck, params, isSysDefault, patternPass, lengthPass, hasMessage);
                if (x != null) return x;
            }
        }
        return Constants.SUCCESS_STR;
    }

    private String checkPatternAndLenght(ParamEntity paramCheck, Map<String, Object> params, boolean isSysDefault, boolean patternPass, boolean lengthPass, boolean hasMessage) {
        if (!patternPass || !lengthPass){
            if (isSysDefault){
                if (hasMessage){
                    return Constants.MESSAGE + paramCheck.getMessage();
                }
                return paramCheck.getValue();
            }
            params.put(paramCheck.getValue(),paramCheck.getDefaultValue());
        }
        return null;
    }

}
